//@ts-nocheck
import * as THREE from "three"
import configConst from "../constant/config.const"
import CameraData from "../data/CameraData"
import CanvasData from "../data/CanvasData"
import { SceneChildType } from "../enum/scene.enum"
import TextureLoader from "../loader/TextureLoader"
import be from "../shader/2209"
import p from "../shader/31090"
import ce from "../shader/63862"
import de from "../shader/64116"
import m from "../shader/69383"
import ae from "../shader/79826"
import SymbolList from "../SymbolList"
import LineSegment from "../three/LineSegment"
import funcUtil from "../utils/func.util"
import Module from "./Module"
var n = {
  0: "LINE_DEFAULT",
  1: "LINE_HOVER",
  2: "END_DEFAULT",
  3: "END_HOVER",
  END_DEFAULT: 2,
  END_HOVER: 3,
  LINE_DEFAULT: 0,
  LINE_HOVER: 1
}

class LineTextures {
  textures: { [x: number]: THREE.Texture }
  constructor() {
    const e = TextureLoader(
        ""
      ),
      t = TextureLoader(
        ""
      ),
      i = TextureLoader(
        ""
      ),
      s = TextureLoader(
        ""
      )
    this.textures = {
      [n.LINE_DEFAULT]: i,
      [n.LINE_HOVER]: s,
      [n.END_DEFAULT]: e,
      [n.END_HOVER]: t
    }
    i.minFilter = THREE.LinearFilter
    s.minFilter = THREE.LinearFilter
    e.minFilter = THREE.LinearFilter
    t.minFilter = THREE.LinearFilter
  }
  get(e) {
    return this.textures[e]
  }
  dispose() {
    for (const e in this.textures) {
      const t = Number(e)
      this.get(t).dispose()
    }
  }
}
const f = {
  endpoint: {
    uniforms: {
      opacity: { type: "f", value: 1 },
      color: { type: "c", value: new THREE.Color() },
      bg: { type: "t", value: null }
    },
    vertexShader: funcUtil.addNR(m, ae),
    fragmentShader: funcUtil.addNR(p, be)
  },
  line: {
    uniforms: THREE.UniformsUtils.merge([
      THREE.UniformsLib.common,
      THREE.UniformsLib.fog,
      {
        linewidth: { value: 4 },
        resolution: { value: new THREE.Vector2(0, 0) },
        dashScale: { value: 1 },
        dashSize: { value: 0.025 },
        gapSize: { value: 0.05 },
        mask: { value: null }
      }
    ]),
    vertexShader: ce,
    fragmentShader: de
  }
}
export class LineMaterial extends THREE.ShaderMaterial {
  parameters: any
  hoverTexture: any
  defaultTexture: any
  selectedWidth: number
  isLineMaterial: boolean
  defaultWidth: number
  constructor(e, t?, i?, n = configConst.lineConfig.lineSelected) {
    super()
    this.parameters = e
    this.hoverTexture = t
    this.defaultTexture = i
    this.selectedWidth = n
    this.type = "LineMaterial"
    this.isLineMaterial = !0
    this.defaultWidth = configConst.lineConfig.lineDefault
    this.setValues({
      uniforms: THREE.UniformsUtils.clone(f.line.uniforms),
      vertexShader: f.line.vertexShader,
      fragmentShader: f.line.fragmentShader,
      transparent: !0,
      depthWrite: !1,
      depthTest: !0,
      opacity: 1
    })
    this.setValues(e)
    i && (this.mask = i)
    this.defaultWidth = e && e.linewidth ? e.linewidth : configConst.lineConfig.lineDefault
  }
  updateSelected(e) {
    const t = e ? this.hoverTexture : this.defaultTexture
    t && this.mask !== t && ((this.mask = t), e ? this.setLinewidth(this.selectedWidth) : this.setLinewidth(this.defaultWidth))
  }
  setLinewidth(e) {
    this.uniforms.linewidth || (this.uniforms = THREE.UniformsUtils.clone(f.line.uniforms)), this.getLinewidth() !== e && (this.uniforms.linewidth.value = e)
  }
  getLinewidth() {
    return this.uniforms.linewidth.value
  }
  get color() {
    return this.uniforms.diffuse.value
  }
  set color(e) {
    this.uniforms.diffuse.value = e
  }
  getOpacity() {
    return this.uniforms.opacity.value
  }
  setOpacity(e) {
    this.uniforms || (this.uniforms = THREE.UniformsUtils.clone(f.line.uniforms)), this.getOpacity() !== e && (this.uniforms.opacity.value = e)
  }
  get dashScale() {
    return this.uniforms.dashScale.value
  }
  set dashScale(e) {
    this.uniforms.dashScale.value = e
  }
  set dashed(e) {
    e ? (this.defines.USE_DASH = "") : delete this.defines.USE_DASH, (this.needsUpdate = !0)
  }
  get dashed() {
    return "USE_DASH" in this.defines
  }
  get dashSize() {
    return this.uniforms.dashSize.value
  }
  set dashSize(e) {
    this.uniforms.dashSize.value = e
  }
  get gapSize() {
    return this.uniforms.gapSize.value
  }
  set gapSize(e) {
    this.uniforms.gapSize.value = e
  }
  get resolution() {
    return this.uniforms.resolution.value
  }
  set resolution(e) {
    this.uniforms.resolution.value = e
  }
  set mask(e) {
    this.uniforms.mask.value !== e && (e ? (this.defines.USE_MASK = "") : delete this.defines.USE_MASK, (this.uniforms.mask.value = e), (this.needsUpdate = !0))
  }
  get mask() {
    return this.uniforms.mask.value
  }
  copy(e) {
    THREE.ShaderMaterial.prototype.copy.call(this, e)
    this.parameters = e.parameters
    this.color.copy(e.color)
    this.defaultWidth = e.defaultWidth
    this.setLinewidth(e.getLinewidth())
    this.resolution.copy(e.resolution)
    this.defaultTexture = e.defaultTexture
    this.hoverTexture = e.hoverTexture
    this.mask = e.mask
    this.setOpacity(e.getOpacity())
    this.dashed = e.dashed
    this.dashScale = e.dashScale
    this.dashSize = e.dashSize
    this.gapSize = e.gapSize
    return this
  }
}
export class LineEndpointMaterial extends THREE.RawShaderMaterial {
  color: any
  defaultTex: any
  hoverTex: any
  constructor(e, t, i) {
    const n = THREE.UniformsUtils.clone(f.endpoint.uniforms)
    super({
      fragmentShader: f.endpoint.fragmentShader,
      vertexShader: f.endpoint.vertexShader,
      uniforms: n,
      name: "LineEndpointMaterial",
      transparent: !0,
      depthWrite: !1,
      depthTest: !0
    })
    this.color = e
    this.defaultTex = t
    this.hoverTex = i
    this.uniforms.bg.value = t
    this.uniforms.color.value.copy(this.color)
  }
  clone() {
    const that = this
    //@ts-nocheck
    return new LineEndpointMaterial(this.color, this.defaultTex, this.hoverTex).copy(that)
  }
  setOpacity(e) {
    this.uniforms && e !== this.uniforms.opacity.value && (this.uniforms.opacity.value = e)
  }
  getOpacity() {
    return this.uniforms.opacity.value
  }
  updateHovered(e) {
    const t = e ? this.hoverTex : this.defaultTex
    this.uniforms.bg.value !== t && (this.uniforms.bg.value = t)
  }
}
export default class Lines extends Module {
  static makeLineMaterial: any
  static makeEndpointMaterial: any
  makeLineMaterial: any
  makeEndpointMaterial: any
  onCanvasChange: (e: any) => void
  segments: any
  static _textures: LineTextures
  scene: any
  canvas: any
  cameraData: any
  cameraPosition: THREE.Vector3
  constructor() {
    super(...arguments),
      (this.name = "lines"),
      (this.makeLineMaterial = (e, t, i = {}, n, s) => Lines.makeLineMaterial(e, t, i, n, s)),
      (this.makeEndpointMaterial = (e, t, i) => Lines.makeEndpointMaterial(e, t, i)),
      (this.onCanvasChange = e => {
        for (const t of this.segments) t.updateResolution(e.width, e.height)
      })
  }
  static get textures() {
    return Lines._textures || (Lines._textures = new LineTextures()), Lines._textures
  }
  async init(e, t) {
    Lines._textures || (Lines._textures = new LineTextures())
    const i = await t.getModuleBySymbol(SymbolList.WEBGL_RENDERER)
    ;(this.scene = i.getScene()),
      (this.canvas = await t.market.waitForData(CanvasData)),
      (this.cameraData = await t.market.waitForData(CameraData)),
      this.bindings.push(this.canvas.onChanged(this.onCanvasChange)),
      (this.cameraPosition = new THREE.Vector3()),
      (this.segments = [])
  }
  onUpdate() {
    this.cameraPosition.copy(this.cameraData.pose.position)
  }
  dispose(e) {
    super.dispose(e), this.segments.forEach(e => e.dispose())
  }
  makeLine(e, t, i, n, s = () => !1) {
    const r = s() ? configConst.labelConfig.OFFSET_TOWARDS_CAMERA : 0,
      o = s() ? e => this.cameraPosition.clone().sub(e).setLength(r).add(e) : e => e,
      l = new LineSegment(
        e,
        t,
        i,
        {
          beforeUpdatePositions: o,
          onShow: () => l.children.forEach(e => this.scene.addChild(SceneChildType.Root, e)),
          onHide: () => l.children.forEach(e => this.scene.removeChild(SceneChildType.Root, e))
        },
        n
      )
    return l.updateResolution(this.canvas.width, this.canvas.height), l.opacity(1), l.show(), l.updatePositions(e, t), this.segments.push(l), l
  }
}
Lines.makeLineMaterial = (e, t, i = {}, s, r) => {
  const a = r || Lines.textures.get(n.LINE_HOVER),
    l = s || Lines.textures.get(n.LINE_DEFAULT),
    c = new THREE.Vector2(window.innerWidth, window.innerHeight)
  return t
    ? new LineMaterial(Object.assign({ color: new THREE.Color(e), resolution: c }, i), a, l)
    : new LineMaterial(Object.assign({ color: new THREE.Color(e) }, i))
}
Lines.makeEndpointMaterial = (e, t, i) => {
  const s = i || Lines.textures.get(n.END_HOVER),
    r = t || Lines.textures.get(n.END_DEFAULT)
  return new LineEndpointMaterial(new THREE.Color(e), r, s)
}
